• 有两种格式可以在shell中创建函数:

    • 采用关键字function,后跟分配给该代码块的函数名:

      1
      2
      3
      function name {
      commands
      }
    • 更加接近于其他编程语言中定义函数的方式:

      1
      2
      3
      name() {
      commands
      }
  • 要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就可以了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/bin/bash
    #using a function in a script
    function func1 {
    echo "This is an example of a function"
    }
    count=1
    while [ $count -le 5 ]
    do
    func1
    count=[ count + 1 ]
    done
    echo "This is the end of the loop"
    func1
    echo "Now this is the end of the script"
  • bash shell把函数当作一个小型脚本,运行结束时会返回一个退出状态码

    • 默认退出状态码

      默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码,在函数执行结束后,可以用$?来确定函数的退出状态码

    • 使用return命令

      bash shell使用return命令来退出函数并返回特定的退出状态码,return命令允许你指定一个整数值来定义函数的退出状态码。

      1
      2
      3
      4
      5
      6
      7
      8
      #!/bin/bash
      function db1 {
      read -p "Enter a value: " value
      echo "doubling the value"
      return $[ $value * 2 ]
      }
      db1
      echo "The new value is $?"

      使用这种方法从函数中返回值,需小心:

      • 函数一结束就取返回值

      • 退出状态码必须是0~255

      • 如果在用$?变量提取函数返回值之前执行了其他命令,函数的返回值就会丢失。

      • 使用函数输出,将函数的输出保存到变量中:result=’db1’,这个命令将db1函数的输出赋给$result变量:

        1
        2
        3
        4
        5
        6
        7
        #!/bin/bash
        function db1{
        read -p "Enter a value: " value
        echo $[ $value * 2 ]
        }
        result=$(db1)
        echo "The new value is $result"
  • 函数可以使用标准的参数环境变量来表示命令行上传给函数的参数,例如函数名会在$0变量中定义,函数命令行上的任何参数都会通过$1$2等定义,也可以用特殊变量$#来判断传给函数的参数数目:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/bin/bash
    function addem {
    if [ $# -eq 0 ] || [ $# -gt 2 ]
    then
    echo -1
    elif [ $# -eq 1 ]
    then
    echo $[ $1 + $1 ]
    else
    echo $[ $1 + $2 ]
    fi
    }
    echo -n "Adding 10 and 15: "
    value=$(addem 10 15)
    echo $value

    由于函数使用特殊参数环境变量作为自己的参数值,因此无法直接获取脚本在命令行中的参数值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/bin/bash
    function badfunc1 {
    echo $[ $1 * $2 ]
    }
    if [$# -eq 2]
    then
    value=$(badfunc1)
    echo "The result is $value"
    else
    echo "Usage: badtest1 a b"
    fi

    尽管函数也使用了$1$2变量,但它们和脚本主体中的$1$2变量并不相同,要在函数中使用这些值,必须在调用函数时手动将它们传过去。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/bin/bash
    function func {
    echo $[ $1 * $2 ]
    }
    if [$# -eq 2]
    then
    value=$(func $1 $2)
    echo "The result is $value"
    else
    echo "Usage: badtest a b"
    fi
  • 在函数内部使用的任何变量都可以被声明为局部变量,只要在变量声明的前面加上local关键字即可:local temp,当然也可以在变量赋值语句中使用local关键字:

    1
    local temp=[ value + 5 ]
  • 向函数传数组参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/bin/bash
    functon testit {
    echo "The parameters are: $@"
    thisarray=$1
    echo "The received array is ${thisarray[*]}"
    }
    myarray=(1 2 3 4 5)
    echo "The original array is: ${myarray[*]}"
    testit $myarray
    1
    2
    3
    4
    $ ./badtest3
    The original array is: 1 2 3 4 5
    The parameters are: 1
    The received array is 1

    如果你试图将数组变量作为函数参数,函数只会取数组变量的第一个值,要解决这个问题,你可以将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用,在函数内部,可以将所有的参数重新组合成一个新的变量:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/bin/bash
    function testit {
    local newarray
    newarray=('echo "$@"')
    echo "The new array value is: ${newarray[*]}"
    }
    myarray=(1 2 3 4 5)
    echo "The original array is ${myarray[*]}"
    testit ${myarray[*]}

    另一个例子如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/bin/bash
    function addarray {
    local sum=0
    local newarray
    newarray=($(echo "$@"))
    for value in ${newarray[*]}
    do
    sum=$[ $sum + $value ]
    done
    echo $sum
    }
    myarray=(1 2 3 4 5)
    echo "The original array is ${myarray[*]}"
    arg1=$(echo {myarray[*]})
    result=$(addarray arg1)
    echo "The result is $result"
  • 从函数里向shell脚本传回数组变量可以使用echo语句按正确顺序输出单个数组值,然后脚本再将它们放进一个新的数组变量中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/bin/bash
    function arraydblr {
    local orginarray
    local newarray
    local elements
    local i
    originarray=((echo "$@"))
    newarray=((echo "$@"))
    elements=[ $# - 1 ]
    for (( i = 0; i <= $elements; i++ )) {
    newarray[$i]=$[ ${originarray[$i]} * 2 ]
    }
    echo ${newarray[*]}
    }
    myarray=(1 2 3 4 5)
    echo "The original array is: ${myarray[*]}"
    arg1=(echo ${myarray[*]})
    result=($(arraydblr arg1))
    echo "The new array is: ${result[*]}"
  • 给一个递归的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/bin/bash
    function factorial {
    if [ $1 -eq 1 ]
    then
    echo 1
    else
    local temp=$[ $1 - 1 ]
    local result=$(factorial $temp)
    echo $[ $result * $1 ]
    fi
    }
    read -p "Enter value: " value
    result=(factorial $value)
    echo "The factorial of value is: $result"
  • bash shell 允许创建库文件,然后在多个脚本中引用该库文件,这个过程的第一步就是创建一个包含脚本中所需函数的公用库文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $cat myfuncs
    function addem {
    echo $[ $1 + $2 ]
    }
    function multem {
    echo $[ $1 * $2 ]
    }
    function divem {
    if ($2 -ne 0)
    then
    echo $[ $1 / $2 ]
    else
    echo -1
    fi
    }

    下一步就是在用到这些函数的脚本文件中包含myfuncs库文件,和环境变量一样,shell函数仅在定义它的shell会话内有效,如果你在shell命令行界面的提示符下运行myfuncs shell脚本,shell会创建一个新的shell并在其中运行这个脚本,它会为那个新的shell定义这三个函数,但当你运行另外一个要用到这些函数的脚本时,它们是无法使用的。

    使用函数库的关键在于source命令,source命令会在当前shell上下文中执行命令,而不是创建一个新的shell,可以用source命令在shell脚本中运行库文件脚本,这样脚本就可以使用库中的函数了。

    source命令有个快捷的别名,称作点操作符,要在shell脚本中运行myfuncs库文件,只需要这样:. ./myfuncs:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/bash
    . ./myfuncs
    value1=10
    value2=5
    result1=(addem $value1 $value2)
    result2=(multem $value1 $value2)
    result3=(diven $value1 $value2)
    echo "The result of adding them is: $result1"
    echo "The result of multiplying them is: $result2"
    echo "The result of dividing them is: $result3"
  • 在命令行上创建函数:

    • 采用单行方式定义参数:

      1
      2
      3
      4
      $ function divem { echo $[ $1 + $2 ]; }
      $ divem 100 5
      20
      $

      当在命令行上定义函数时,需要在每个命令后面加上分号,这样shell就能知道在哪里是命令的起止了。

    • 采用多行方式定义函数:

      1
      2
      3
      4
      5
      6
      $ function multem {
      > echo [ 1 * $2 ]
      > }
      $ multem 2 5
      10
      $

      在函数的尾部使用花括号,shell就会知道你已经完成了函数的定义。

  • 在命令行上定义的函数在退出shell时函数就会消失,一个好的方法就是将函数定义在一个特定的位置,这个位置在每次启动一个新shell的时候,都会由shell重新载入。

    可以将函数放在.bashrc中,有两种方法:

    • 直接在.bashrc文件中定义函数
    • 读取函数文件,只要是在shell脚本中,都可以使用source命令将库文件中的函数添加到你的.bashrc脚本中

    更好的是,shell还会将定义好的函数传给子shell进程,这样一来,这些函数就自动能够用于该shell会话的任何sehll脚本了